
(function ($) {
  $.fn.yqLayoutUI = function (opts, param) {
    if (typeof opts == 'string') {
      return $.fn.yqLayoutUI.methods[opts](this, param);
    }

    var $this = this;
    var opt;
    if ($this.data("yqtype") == "yqLayoutUI") {
      var $uniqueID = $this.attr("ID");
      var opts_ = $.extend({}, options($this));
      destroy($this);
      $this = $("#" + $uniqueID);
      opt = $.extend(opts_, opts);
    }
    else {
      opt = $.extend({}, $.fn.yqLayoutUI.defaults, opts);
      var $uniqueID = $this.attr("ID");
      if ($uniqueID === undefined || $uniqueID === null || $uniqueID == "") {
        $uniqueID = $.getUniqueID();
        $this.attr("ID", $uniqueID);
      }
    }

    if (opt.width === undefined && $this.width() > 0) {
      opt.width = $this.width();
    }
    else if (typeof opt.width != "undefined") {
      $this.width(opt.width);
    }

    if (opt.height === undefined && $this.height() > 0) {
      opt.height = $this.height();
    }
    else if (typeof opt.height != "undefined") {
      $this.height(opt.height);
    }

    //转换编辑尺寸
    opt.width = $.whFormat(opt.width);
    opt.height = $.whFormat(opt.height);
 
    opt.cont_num = 0;       //容器序号
    opt.item_num = 0;     //内容序号
    opt.accept_class = "dragitem";  //拖放对象class标记
    opt.editor_class = "drageditor"; //编辑对象容器class标记
    opt.$select = {};      //容器对象
    opt.$select_view = {}; //内容对象
    opt.$item_over = {};   //内容over对象
    opt.$drag_item;        //当前拖放的对象

    //变量信息
    $this.data("yqlayoutui_opt", opt);
    $this.data("yqtype", "yqLayoutUI");
    loadJsCss($this, function () {
      init_layout($this); 
    });
  };

  $.fn.yqLayoutUI.defaults = {
    //width: 1200,
    //height: 900,
    //前缀“_”标记为容器组件
    dragitems: [{
      title: "布局设置"
    }, {
      name: "_tb",
      title: "table",
      tag: "td",
      titles: [{
        "name": "rows",
        "ui_title": "行",
        "fd_type": "int",
        "length": 10,
        "decimal": 0,
        "ui_type": 10,
        "ui_width": 90,
        "ui_visible": true,
        "ui_readnnly": false,
        "ui_mask": {
          "default": 3,
          "min": 1,
          "max": 50,
          "blank": false
        }
      }, {
        "name": "cols",
        "ui_title": "列",
        "fd_type": "int",
        "length": 10,
        "decimal": 0,
        "ui_type": 10,
        "ui_width": 90,
        "ui_visible": true,
        "ui_readnnly": false,
        "ui_mask": {
          "default": 3,
          "min": 1,
          "max": 50,
          "blank": false
        }
      }],
      params: { rows: 2, cols: 2 },
      getValue: function () {
        var params = this.params;
        var $tb = $('<table></table>');
        for (let i = 0; i < params.rows; i++) {
          var $tr = $("<tr></tr>");
          $tb.append($tr);
          for (let j = 0; j < params.cols; j++) {
            var $td = $("<td></td>");
            $tr.append($td);
          }
        }
        return $tb.prop("outerHTML");
      },
      getParams: function ($object, $inner) {
        var $tbody = $inner.children("tbody");
        var $trs;
        if ($tbody.length == 0) {
          $trs = $inner.children();
        } else {
          $trs = $($inner.children()[0]).children();
        }
        var cols = 1;
        for (let i = 0; i < $trs.length; i++) {
          const $tds = $($trs[i]).children();
          if (cols < $tds.length) {
            cols = $tds.length;
          }
        }

        return { rows: $trs.length, cols: cols }
      },
      update: function ($object, $inner, params) {
        // 对象解码后进行处理数据
        var $o_html = $(update_GetHtml($object, $inner))
        var $tbody = $o_html.children("tbody");
        var $trs;
        if ($tbody.length == 0) {
          $trs = $o_html.children();
        } else {
          $trs = $($o_html.children()[0]).children();
        }
        var rows = [];
        for (let i = 0; i < $trs.length; i++) {
          const $tds = $($trs[i]).children();
          for (let j = 0; j < $tds.length; j++) {
            var row = { rownum: i, colnum: j, value: $($tds[j]).html() };
            rows.push(row);
          }
        }

        var $tb = $('<table></table>');
        for (let i = 0; i < params.rows; i++) {
          var $tr = $("<tr></tr>");
          $tb.append($tr);
          for (let j = 0; j < params.cols; j++) {
            var $td = $("<td></td>");
            var $html = "";
            for (let n = 0; n < rows.length; n++) {
              if (rows[n].rownum == i && rows[n].colnum == j) {
                $html = rows[n].value;
                break;
              }
            }
            $td.html($html);
            $tr.append($td);
          }
        }

        var newhtml = $tb.prop("outerHTML");
        update_UppEdit($object, $inner, newhtml);
      }
    }, {
      title: "Base"
    }, {
      name: "lable",
      title: "Lable",
      getValue: function () {
        return '<lable>' + this.title + '</lable>';
      }
    }, {
      name: "textbox",
      title: "Textbox",
      titles: [{
        "name": "width",
        "ui_title": "宽度(px)",
        "fd_type": "int",
        "length": 10,
        "decimal": 0,
        "ui_type": 10,
        "ui_width": 90,
        "ui_visible": true,
        "ui_readnnly": false,
        "ui_mask": {
          "default": 3,
          "min": 30,
          "max": 1200,
          "blank": false
        }
      }],
      params: { width: 120 },
      getValue: function () {
        return '<input type="text" style="width:' + this.params.width + 'px;"/>';
      },
      getParams: function ($object, $inner) {
        //console.log($inner.prop("outerHTML"));
        var width = $inner.css("width")
        if (width === undefined) {
          width = $inner.css("width");
        } else {
          width = parseInt(width);
        }
        return { width: width }
      },
      update: function ($object, $inner, params) {
        $inner.width(params.width);
      }
    }, {
      name: "select",
      title: "Select",
      titles: [{
        "sid": "6",
        "name": "type",
        "is_func": false,
        "ui_title": "Type",
        "fd_type": "int",
        "length": 16,
        "decimal": 0,
        "ui_type": 6,
        "ui_width": 90,
        "ui_visible": true,
        "ui_readnnly": false,
        "ui_mask": "{\"lists\":[{\"no\":1,\"name\":\"下拉\"},{\"no\":2,\"name\":\"点选\"}]}"
      }, {
        "name": "width",
        "ui_title": "宽度(px)",
        "fd_type": "int",
        "length": 10,
        "decimal": 0,
        "ui_type": 10,
        "ui_width": 90,
        "ui_visible": true,
        "ui_readnnly": false,
        "ui_mask": {
          "default": 3,
          "min": 30,
          "max": 1200,
          "blank": false
        }
      }],
      params: { type: 1, width: 120 },
      getValue: function () {
        if (this.params.type == 1) {
          return '<select style="width: ' + this.params.width + 'px"></select>';
        } else {
          return '<div style="width: ' + this.params.width + 'px">[' + this.title + ']</div>';
        }
      },
      getParams: function ($object, $inner) {
        var width = $inner.css("width")
        if (width === undefined) {
          width = $inner.css("width");
        } else {
          width = parseInt(width);
        }

        var params = { width: width };
        if ($inner[0].tagName.toLowerCase() == "select") {
          params.type = 1;
        } else {
          params.type = 2;
        }

        return params
      },
      update: function ($object, $inner, params) {
        var newhtml;
        if (params.type == 1) {
          newhtml = '<select style="width: ' + params.width + 'px"></select>';
        } else {
          newhtml = '<div style="width: ' + params.width + 'px">[' + this.title + ']</div>';
        }
        update_UppEdit($object, $inner, newhtml);
      }
    }, {
      name: "checkbox",
      title: "Checkbox",
      getValue: function () {
        return '<input type="checkbox" />';
      }
    }, {
      name: "textarea",
      title: "Textarea",
      titles: [{
        "name": "width",
        "ui_title": "宽度(px)",
        "fd_type": "int",
        "length": 10,
        "decimal": 0,
        "ui_type": 10,
        "ui_width": 90,
        "ui_visible": true,
        "ui_readnnly": false,
        "ui_mask": {
          "default": 3,
          "min": 30,
          "max": 1200,
          "blank": false
        }
      }, {
        "name": "height",
        "ui_title": "高度(px)",
        "fd_type": "int",
        "length": 10,
        "decimal": 0,
        "ui_type": 10,
        "ui_width": 90,
        "ui_visible": true,
        "ui_readnnly": false,
        "ui_mask": {
          "default": 3,
          "min": 30,
          "max": 1200,
          "blank": false
        }
      }],
      params: { width: 200, height: 50 },
      getValue: function () {
        return '<textarea  style="height: ' + this.params.height + 'px; width: ' + this.params.width + 'px"></textarea>';
      },
      getParams: function ($object, $inner) {
        var width = $inner.css("width");
        var height = $inner.css("height");
        return { width: width, height: height }
      },
      update: function ($object, $inner, params) {
        $inner.width(params.width);
        $inner.height(params.height);
      }
    }, {
      title: "Titles"
    }, {
      id: "lbl_name",
      name: "lable",
      title: "lblName"
    }, {
      id: "txt_name",
      name: "textbox",
      title: "txtName",
      params: { width: 120 }
    }, {
      id: "lbl_code",
      name: "lable",
      title: "lblCode"
    }, {
      id: "txt_code",
      name: "textbox",
      title: "txtCode",
      params: { width: 120 }
    }],
    value: ""
  };

  $.fn.yqLayoutUI.methods = {
    options: function (jq) {
      return options(jq);
    },
    destroy: function (jq) {
      destroy(jq);
    },
    resize: function (jq, params) {
      resize(jq, params);
    },
    clear: function (jq) {
      setValue(jq, null);
    },
    setValue: function (jq, value) {
      setValue(jq, value);
    },
    getValue: function (jq) {
      return getValue(jq);
    },
    isEdit: function (jq, tf) {
      isEdit(jq, tf);
    },
    update_GetHtml: function (jq, $inner) {
      return update_GetHtml(jq, $inner);
    },
    update_UppEdit: function (jq, params) {
      update_UppEdit(jq, params.$inner, params.f_html);
    }
  };

  function options($object) {
    return $object.data("yqlayoutui_opt");
  }

  function page_load($object) {
    var opt = options($object);
    opt.$east.panel("options").onResize = function (width, height) {
      if (opt.setResizeTime === undefined) {
        opt.setResizeTime = setTimeout(function () {
          //console.log(width, height);
          resize($object);
        }, 100);
      }
    };
    //修改尺寸
    resize($object);
    //初始化赋值
    setValue($object, opt.value);
  }

  function resize($object, params) {
    var opt = options($object);
    if (typeof params == "object") {
      if (typeof params.width != "undefined") {
        opt.width = params.width;
      }
      if (typeof params.height != "undefined") {
        opt.height = params.height;
      }
    }

    opt.$lo.layout("resize", {
      width: opt.width,
      height: opt.height
    });

    opt.$tabs.tabs("resize", {
      width: $(opt.$center).width(),
      height: $(opt.$center).height()
    });

    opt.$editor.height($(opt.$center).height() - 36);
    opt.$code.height($(opt.$center).height() - 36);
    opt.ace.resize();

    opt.$attredit.propertygrid("resize", { width: opt.$east.width(), height: opt.$east.height() });
 
    if (!(opt.setResizeTime === undefined)) {
      clearInterval(opt.setResizeTime);
      opt.setResizeTime = undefined;
    }
  }

  function destroy($object) {
    var opt = options($object);
    opt.ace.destroy();
    $object.find(".layoutui").remove();
    $object.removeData("foreignkey_opt");
    $object.removeData("yqtype");
  }

  function loadJsCss($object, callback) {
    var opt = options($object);
    var file = [];
    file.push({ url: "/yqwin/src/themes/yq.layoutui.css", type: "css" });
    file.push({ url: "/scripts/ace/ace.js", type: "js" });
    file.push({ url: "/scripts/ace/mode-html.js", type: "js" });
    $.yqLoadJsCss(file, function () {
      callback();
    })
  }

  function init_layout($object) {
    var opt = options($object);

    var $lo = $('<div class="layoutui"></div>');
    opt.$lo = $lo;
    $object.append($lo);
    $lo.layout({
      width: opt.width,
      height: opt.height
    });

    $lo.layout('add', {
      region: 'west',
      title: "控件",
      width: 180,
      split: true
    });

    $lo.layout('add', {
      region: 'center'
    });

    $lo.layout('add', {
      region: 'east',
      width: 180,
      split: true,
    });
    //$lo.layout('collapse',  'east' );

    var $west = $lo.layout('panel', 'west');
    opt.$west = $west;
    $west.append('<div class="selectmenu" style="width:100%"></div>');
    var $center = $lo.layout('panel', 'center');
    opt.$center = $center;

    var $tabs = $("<div></div>");
    opt.$tabs = $tabs;
    $center.append($tabs);
    $tabs.tabs({
      border: false,
      tabPosition: 'bottom',
      onSelect: function (title) {
        //alert(title + ' is selected');
      }
    });

    $tabs.tabs('add', {
      title: 'view'
    });
    $tabs.tabs('add', {
      title: 'code'
    });

    $tabs.tabs('select', 0);
    $tabs.tabs('options').onSelect = function (title) {
      var $this = $(this)
      var tab = $this.tabs('getSelected');
      var index = $this.tabs('getTabIndex', tab);
      //alert(index);
      if (index == 0) {
        var html = opt.ace.getValue();
        setValue($object, html);
      } else if (index == 1) {
        var html = getValue($object);
        var cursor = opt.ace.selection.getCursor();
        opt.ace.setValue(html);
        opt.ace.gotoLine(cursor.row);
        opt.ace.moveCursorTo(cursor.row, cursor.column);

        item_click($object);
      }
    };

    var $body_0 = $tabs.tabs('getTab', 0).panel('body');
    var $editor = $('<div></div>');
    opt.$editor = $editor;
    $editor.addClass(opt.editor_class);
    $editor.css({ width: '100%', height: '500px' });
    $body_0.append($editor);

    var $body_1 = $tabs.tabs('getTab', 1).panel('body');
    var $code = $('<div></div>');
    opt.$code = $code;
    $code.css({ width: '100%', height: '500px' });
    opt.codeareaId = $object.attr('id') + '_code';
    $code.attr("id", opt.codeareaId);
    $body_1.append($code);


    var $east = $lo.layout('panel', 'east');
    opt.$east = $east;
    var $attredit = $('<table></table>');
    $east.append($attredit);
    opt.$attredit = $attredit;

    var $sm = $object.find(".selectmenu");
    opt.$sm = $sm;
    var $ul = null;
    for (let i = 0; i < opt.dragitems.length; i++) {
      var item = opt.dragitems[i];
      if (item.name === undefined) {
        var $div = $('<div title="' + item.title + '"><ul></ul></div>');
        $ul = $div.find("ul");
        $sm.append($div);
      } else {
        opt.dragitems[i] = $.extend({
          view_add: '',
          titles: [],
          params: {},
          getParams: function ($object, $inner) {
            return {};
          },
          update: function ($object, $inner, params) { }
        }, item);
        item = opt.dragitems[i];

        if (!(item.name === undefined)) {
          var h_r = `<li>
                          <span>$title</span>
                          <a class="dragitem fa fa-arrows" href="javascript:void(0);"></a>
                      </li>`;
          h_r = h_r.replace("$title", item.view_add + item.title);
          var $li = $(h_r);
          if (item.id === undefined) {
            $li.find(".dragitem").attr("_n", item.name);
          } else {
            for (let j = 0; j < opt.dragitems.length; j++) {
              var item_ = opt.dragitems[j];
              if (item.name == item_.name && item_.id === undefined) {
                if (typeof item_.titles == "object") {
                  item.titles = item_.titles;
                }
                item.params = $.extend({}, item_.params);
                break;
              }
            }
            $li.find(".dragitem").attr("_id", item.id);
          }

          if (item.titles.length > 0) {
            var $edit = $('<a name="' + item.name + '" class="edit fa fa-cog" href="javascript:void(0);"></a>');
            if (!(item.id === undefined)) {
              $li.find(".dragitem").attr("_id", item.id);
              $edit.attr("id_", item.id);
            }
            $edit.bind('click', function () {
              setItemParams($object, $(this));
            });
            $li.find(".dragitem").after($edit);
          }

          if ($ul === null) {
            var $div = $('<div title="' + item.view_add + item.title + '"><ul></ul></div>');
            $ul = $div.find("ul");
            $sm.append($div);
          }
          $ul.append($li);
        }
      }
    }

    $sm.accordion({
      animate: false
    });


    $attredit.propertygrid({
      border: false,
      toolbar: [{
        id: "btn_d_item_del",
        text: "删除",
        iconCls: 'icon2-del',
        size: "small",
        handler: function () {
          update_del($object, opt.select_item);
          item_click($object);
        },
      }, '-'
      ],
      columns: [[
        {
          field: 'name', title: '名称', width: '40%'
        }, {
          field: 'value',
          title: '值',
          width: '42%',
          formatter: function (value, row, index) {
            return $.yqPgFormatter.call(this, {
              value: value,
              row: row,
              index: index,
              field: "value",
              ui_type: row.ui_type,
              ui_mask: row.ui_mask
            });

          }
        }
      ]],
      showGroup: true,
      groupField: "group",
      // groupFormatter:function(group,rows){
      //     console.log(group,rows);  
      // },
      scrollbarSize: 0,
      onAfterEdit: function (index, row, changes) {
        var props1 = Object.getOwnPropertyNames(changes);
        if (props1.length > 0) {
          var edit_opt = $(this).propertygrid("options");
          edit_opt.edit_items;
          var rows = $(this).propertygrid("getRows")
          var row = {};
          for (let i = 0; i < rows.length; i++) {
            const row_ = rows[i];
            if (row_["field"].substring(0, 1) != "_") {
              row[row_["field"]] = row_["value"];
            }
          }

          if (edit_opt.edit_items.id_item === undefined) {
            edit_opt.edit_items.name_item.update.call(edit_opt.edit_items.name_item, $object, edit_opt.edit_items.inner, row);
          } else {
            edit_opt.edit_items.name_item.update.call(edit_opt.edit_items.id_item, $object, edit_opt.edit_items.inner, row);
          }

          console.log(row, edit_opt.edit_items);
        }
      }
    });

    $("#btn_d_item_del").linkbutton("disable");

    //可拖放对象
    dragAction($object, $object.find('.dragitem'));
    //容器对象
    acceptAction($object, $editor, 1);

    setCodeView($object);

    page_load($object);
  }

  function setCodeView($object) {
    var opt = options($object);
    opt.ace = ace.edit(opt.codeareaId);
    opt.ace.setFontSize(14);
    opt.ace.session.setMode('ace/mode/html');
    opt.ace.session.setTabSize(4);
    opt.ace.session.setUseSoftTabs(true);
    opt.ace.session.setOption('useWorker', false);
    opt.ace.renderer.setOption('vScrollBarAlwaysVisible', true);
  }

  function setItemParams($object, $this) {
    var opt = options($object);
    var _name = $this.attr("name");
    var _id = $this.attr("id_");
    var items = getItem($object, _name, _id);
    var $s_item;
    if (items.id_item === undefined) {
      $s_item = items.name_item;
    } else {
      $s_item = items.id_item;
    }

    var prevent_e = $.getPreventDefault($this[0]);
    //console.log("prevent_e", prevent_e);
    prevent_e.clientY += 23;
    var mdiinfo = $.yqGetWindParams();

    var run_opt = {
      mdiinfo: mdiinfo,
      prevent_e: prevent_e,
      titles: $s_item.titles,
      action: "add",
      row: $s_item.params,
      isEdit: true,
      loadDefault: true,   //加载默认值
      width: 300,
      height: 33 * $s_item.titles.length + 50,
      callback: function (row_) {
        $s_item.params = row_;
        //console.log(row_);
      }
    };
    if (window.top == window.self) {
      $.yqAttrPopEdit(run_opt);
    }
    else {
      window.top.$.yqAttrPopEdit(run_opt);
    }
  }

  function getItemValue($object, $source) {
    var _name = $source.attr("_n");
    var _id = $source.attr("_id");

    var items = getItem($object, _name, _id);
    if (items.name_item === undefined) {
      return "";
    }

    if (items.id_item === undefined) {
      var $value = $(items.name_item.getValue.call(items.name_item));
      $value.attr("_n", items.name_item.name);
      return $value.prop("outerHTML");
    } else {
      var $value = $(items.name_item.getValue.call(items.id_item));
      $value.attr("id", items.id_item.id);
      return $value.prop("outerHTML");
    }
  }

  function getItem($object, _name, _id) {
    var opt = options($object);
    var id_item;
    var name_item;

    if (!(_id === undefined)) {
      for (let i = 0; i < opt.dragitems.length; i++) {
        const item = opt.dragitems[i];
        if (item.id == _id) {
          id_item = item;
          _name = item.name;
          break;
        }
      }
    }

    for (let i = 0; i < opt.dragitems.length; i++) {
      const item = opt.dragitems[i];
      if (item.name == _name && item.id === undefined) {
        name_item = item;
        break;
      }
    }

    return { id_item: id_item, name_item: name_item }
  }

  //参数初始化
  function init_params($object) {
    var opt = options($object);

    opt.$select = {};      //容器对象
    opt.$select_view = {}; //内容对象
    opt.$item_over = {};  //内容over对象
    opt.$drag_item = undefined;       //当前拖放的对象
  }

  //控件可拖放
  function dragAction($object, $d_obj) {
    var opt = options($object);
    //可拖放对象
    $d_obj.draggable({
      revert: true,
      deltaX: 10,
      deltaY: 10,
      proxy: function (source) {
        var $source = $(source);

        var n = $('<div class="drag_proxy">' + getItemValue($object, $source) + '</div>');
        n.appendTo('body');
        return n;
      },
      onStartDrag: function (e) {
        opt.$drag_item = $(this);
      },
      onEndDrag: function (e) {
        opt.$drag_item = undefined;
      }
    });
  }

  //容器对象
  function acceptAction($object, $accepobj, cont_level) {
    var opt = options($object);

    $accepobj.addClass("c_item");
    $accepobj.attr("cont_level", cont_level);
    opt.cont_num++;
    $accepobj.attr("cont_num", opt.cont_num);

    $accepobj.droppable({
      accept: '.' + opt.accept_class,  //接受对象标识
      onDragEnter: function (e, source) {
        var $this = $(this);
        var $source = $(source);
        //检查循环嵌套
        if ($source.hasClass("d_drag")) {
          var s_a_num = $source.parent().attr("item_num");
          var target = $(this).closest('div.d_item');
          while (target.length > 0) {
            var a_num_ = target.attr("item_num");
            if (s_a_num == a_num_) {
              upSelectTag($object, $source);
              return;
            }
            target = target.parent().closest('div.d_item');
          }
        }

        var a_level = $this.attr("cont_level");
        opt.$select["level" + a_level] = $this;
        var props = Object.getOwnPropertyNames(opt.$select);
        for (let i = 0; i < props.length; i++) {
          var s_level = parseInt(props[i].substring(5));
          if (a_level < s_level) {
            a_level = s_level;
          }
          opt.$select[props[i]].removeClass("con_select");
        }

        upSelectTag($object, $source);
      },
      onDragLeave: function (e, source) {
        var $this = $(this);
        var a_level = $this.attr("cont_level");
        delete opt.$select["level" + a_level];
        $this.removeClass("con_select");

        upSelectTag($object, $(source));
      },
      onDrop: function (e, source) {
        //拖拽处理
        var $source = $(source);
        upSelectTag($object, $source, function ($item, a_level) {
          var _html;
          if ($source.hasClass("d_drag")) {
            var $div = $("<div></div>");
            $div.append($source.parent());
            _html = getHtml($object, $div);
            $div.remove();
          } else {
            _html = getItemValue($object, $source)

            //_html = $source.parent().find(".content").html();
          }

          //初始化参数
          init_params($object);

          var $html = initEdit($object, _html, a_level);
          if ($item.hasClass("view_select")) {
            $item.removeClass("view_select")
            $item.parent().before($html);
          } else {
            $item.removeClass("con_select")
            $item.append($html);
          }

          item_click($object, $html)
        });
      }
    });
  }

  function upSelectTag($object, $source, callback) {
    var opt = options($object);

    var a_level = -1;

    var props = Object.getOwnPropertyNames(opt.$select);
    var props_view = Object.getOwnPropertyNames(opt.$select_view);

    for (var i = 0; i < props.length; i++) {
      var s_level = parseInt(props[i].substring(5));
      if (s_level > a_level) {
        a_level = s_level;
      }
    }

    var $s_item;
    if (a_level > 0) {
      $s_item = opt.$select["level" + a_level];
    } else {
      $s_item = $(".drageditor");
    }

    if (props_view.length == 0) {
      $s_item.addClass("con_select");
      if (typeof callback == "function") {
        callback($s_item, a_level);
      }
    } else {
      var v_level = -1;
      for (var i = 0; i < props_view.length; i++) {
        var s_level = parseInt(props_view[i].substring(5));
        if (s_level > v_level) {
          v_level = s_level;
        }
      }

      var $s_view = opt.$select_view["level" + v_level];
      var select_view_pnum = parseInt($s_view.parent().parent().attr("cont_num"));
      var select_pnum = -1;
      if ($source.hasClass("d_drag")) {
        select_pnum = parseInt($source.parent().parent().attr("cont_num"));
      } else {
        select_pnum = parseInt($s_item.attr("cont_num"));
      }

      var select_pnum = parseInt($s_item.attr("cont_num"));
      if ($source.hasClass("d_drag")) {
        var source_pnum = parseInt($source.parent().parent().attr("cont_num"));
        //插入前端 或 移动
        if (select_view_pnum == select_pnum ||
          (select_view_pnum == source_pnum && source_pnum == select_pnum)) {
          $s_view.addClass("view_select");
          if (typeof callback == "function") {
            callback($s_view, a_level);
          }
        } else {
          $s_item.addClass("con_select");
          if (typeof callback == "function") {
            callback($s_item, a_level);
          }
        }
      } else {
        //插入前端
        if (select_view_pnum == select_pnum) {
          $s_view.addClass("view_select");
          if (typeof callback == "function") {
            callback($s_view, a_level);
          }
        } else {
          $s_item.addClass("con_select");
          if (typeof callback == "function") {
            callback($s_item, a_level);
          }
        }
      }
    }
  }

  function setValue($object, value) {
    var opt = options($object);
    opt.$editor.empty();
    if (!(value === undefined || value === null || value == "")) {
      var $c_obj = initEdit($object, value, 1);
      opt.$editor.append($c_obj);
    }
  }

  function getValue($object) {
    var opt = options($object);
    return getHtml($object, opt.$editor);
  }

  /*
   <div class="d_item">
     <a class="d_drag">拖动</a>
     <a class="d_remove">移除</a>
     <a class="d_view">html......</a>
   </div>
 */

  //加载模板
  function initEdit($object, f_html, f_level) {
    var opt = options($object);

    var $main_obj = $("<div>" + f_html + "</div>");
    get_html($main_obj, f_level);
    return $main_obj.children();

    function get_html($obj, f_level) {
      var $c_s = $obj.children();

      for (let i = 0; i < $c_s.length; i++) {
        const $el = $($c_s[i]);
        var id = $el.attr("id");
        var name;
        if (id === undefined) {
          name = $el.attr("_n");
        } else {
          for (let j = 0; j < opt.dragitems.length; j++) {
            if (opt.dragitems[j].id == id) {
              name = opt.dragitems[j].name;
              break;
            }
          }
        }

        if (!(name === undefined)) {
          edut_item($el, f_level);
          if (name.substring(0, 1) == "_") {
            for (let j = 0; j < opt.dragitems.length; j++) {
              if (opt.dragitems[j].name == name) {
                var in_content = opt.dragitems[j].tag;
                con_tag($el, in_content, f_level);
                break;
              }
            }

            get_html($el, f_level + 1);
          }
        } else {
          get_html($el, f_level);
        }
      }
    }

    function con_tag($obj, in_content, f_level) {
      var $c_s = $obj.children();
      var in_contents = in_content.split(",");
      for (let i = 0; i < $c_s.length; i++) {
        const $el = $($c_s[i]);

        var name = $el.attr("_n")
        if (name === undefined) {
          for (let j = 0; j < in_contents.length; j++) {
            const item = in_contents[j];
            if (item.substring(0, 1) == ".") {
              if ($el.hasClass(item.substring(1))) {
                acceptAction($object, $el, (f_level + 1));
              }
            } else {
              if ($el[0].tagName.toLowerCase() == item.toLowerCase()) {
                acceptAction($object, $el, (f_level + 1));
              }
            }
          }

          con_tag($el, in_content, f_level);
        }
      }
    }

    function edut_item($inner, f_level) {
      opt.item_num++;
      var $html = $('<div class="d_item"></div>');
      $html.attr("a_index", f_level + 1);
      $html.attr("item_num", opt.item_num);
      // if($inner.width()>0){
      //   $html.width($inner.width());
      // }
      $inner.after($html);

      $html.bind("mouseover", function () {
        var $this = $(this);
        opt.$item_over["level" + $this.attr("a_index")] = $this;
        item_over();
      });
      $html.bind("mouseout", function () {
        var $this = $(this);
        delete opt.$item_over["level" + $this.attr("a_index")];
        $this.removeClass("hover");
        item_over();
      });

      $html.bind("click", function () {
        var props = Object.getOwnPropertyNames(opt.$item_over);
        if (props.length > 0) {
          var a_level = -1;
          for (let i = 0; i < props.length; i++) {
            var s_level = parseInt(props[i].substring(5));
            if (a_level < s_level) {
              a_level = s_level;
            }
          }
          var $this = $(this);
          if (parseInt($this.attr("a_index")) == a_level) {
            item_click($object, $this);
          }
        }
      });

      var $drap = $('<a class="d_drag fa fa-arrows"></a>');
      //--- 内部对象拖拽操作 begin --------------
      $drap.addClass(opt.accept_class);
      $drap.draggable({
        revert: true,
        deltaX: 10,
        deltaY: 10,
        proxy: function (source) {
          var n = $('<div class="drag_proxy""></div>');
          n.html($(source).parent().find(".d_view").html()).appendTo('body');
          return n;
        },
        onStartDrag: function (e) {
          opt.$drag_item = $(this);
        },
        onEndDrag: function (e) {
          opt.$drag_item = undefined;
        }
      });
      //--- 内部内部对象操作 end --------------

      // var $remove = $('<a class="d_remove">移除</a>');
      // $remove.bind("click", function () {
      //   var $html = $(this).parent();
      //   update_del($object, $html);
      //   item_click($object);
      // });

      var $view = $('<div class="d_view"></div>');
      $view.append($inner);

      //内容区域接受拖放对象，不能进行数据处理
      $view.droppable({
        accept: '.' + opt.accept_class,  //接受对象标识
        onDragEnter: function (e, source) {
          var $this = $(this);
          var $source = $(source);
          //嵌套排除处理,当前对象不能在source中
          if ($source.hasClass("d_drag")) {
            var s_a_num = $source.parent().attr("item_num");
            var target = $this.parent();
            while (target.length > 0) {
              var a_num_ = target.attr("item_num");
              if (s_a_num == a_num_) {
                upSelectTag($object, $source);
                return;
              }
              target = target.parent().closest('div.d_item');
            }
          }

          var a_level = $this.parent().parent().attr("cont_level");
          opt.$select_view["level" + a_level] = $this;
          var props_view = Object.getOwnPropertyNames(opt.$select_view);
          for (let i = 0; i < props_view.length; i++) {
            var s_level = parseInt(props_view[i].substring(5));
            if (a_level < s_level) {
              a_level = s_level;
            }
            opt.$select_view[props_view[i]].removeClass("view_select");
          }

          upSelectTag($object, $source);
        },
        onDragLeave: function (e, source) {
          var $this = $(this);
          var a_level = $this.parent().parent().attr("cont_level");
          delete opt.$select_view["level" + a_level];

          $this.removeClass("view_select");

          upSelectTag($object, $(source));
        }
      });

      $html.append($drap);
      //$html.append($remove);
      $html.append($view);

      var _id = $inner.attr("id");
      if (_id === undefined) {
        return;
      }
      var $d_item = opt.$sm.find('[_id="' + _id + '"]')
      //console.log(_id,d_item);
      $d_item.draggable("disable");
      $d_item.addClass("disable");
    }

    function item_over() {
      //console.log($item_over);
      //$this.attr("a_index")
      var props = Object.getOwnPropertyNames(opt.$item_over);
      if (props.length > 0) {
        var a_level = -1;
        for (let i = 0; i < props.length; i++) {
          var s_level = parseInt(props[i].substring(5));
          if (a_level < s_level) {
            a_level = s_level;
          }
          opt.$item_over[props[i]].removeClass("hover");
        }

        if (opt.$drag_item === undefined) {
          opt.$item_over["level" + a_level].addClass("hover");
        }
      }
    }
  }

  function item_click($object, $this) {
    var opt = options($object);
    if (!(opt.select_item === undefined)) {
      opt.select_item.removeClass("select");
    }
    if ($this === undefined) {
      opt.select_item = undefined;
      opt.$attredit.propertygrid("loadData", []);
      $("#btn_d_item_del").linkbutton("disable");
      return;
    } else {
      if (!(opt.select_item === undefined) && opt.select_item.attr("item_num") == $this.attr("item_num")) {
        return;
      }

      opt.select_item = $this;
      opt.select_item.addClass("select");
    }

    $("#btn_d_item_del").linkbutton("disable");

    var $inner = $($this.find(".d_view").children()[0]);
    var _id = $inner.attr("id");
    var _name = $inner.attr("_n");
    var items = getItem($object, _name, _id);
    items["inner"] = $inner;
    var edit_opt = opt.$attredit.propertygrid("options");
    edit_opt.edit_items = items;
    if (items.name_item === undefined) {
      opt.$attredit.propertygrid("loadData", []);
      return;
    }

    var titles = [];
    var row = items.name_item.getParams.call(items.name_item, $object, $inner);
    titles.push({
      "name": "_name",
      group: "base",
      "ui_title": "Name",
      "fd_type": "nvarchar",
      "length": 36,
      "decimal": 0,
      "ui_type": 1,
      "ui_width": 90,
      "ui_visible": true,
      "ui_readnnly": true,
      "ui_mask": {}
    });
    row["_name"] = items.name_item.name;
    titles.push({
      "name": "_title",
      group: "base",
      "ui_title": "Title",
      "fd_type": "nvarchar",
      "length": 36,
      "decimal": 0,
      "ui_type": 1,
      "ui_width": 90,
      "ui_visible": true,
      "ui_readnnly": true,
      "ui_mask": {}
    });
    if (items.id_item === undefined) {
      row["_title"] = items.name_item.title;
    } else {
      row["_title"] = items.id_item.title;

      titles.push({
        "name": "_id",
        group: "base",
        "ui_title": "id",
        "fd_type": "nvarchar",
        "length": 36,
        "decimal": 0,
        "ui_type": 1,
        "ui_width": 90,
        "ui_visible": true,
        "ui_readnnly": true,
        "ui_mask": {}
      });
      row["_id"] = items.id_item.id;
    }

    for (let i = 0; i < items.name_item.titles.length; i++) {
      titles.push($.extend({}, items.name_item.titles[i]));
    }

    var rows = [];

    for (let i = 0; i < titles.length; i++) {
      var title = titles[i];
      var value = row[title.name];
      if (value === undefined) {
        value = null;
      }

      var row_ = {
        field: title.name,
        name: title.ui_title,
        value: value
      };
      row_.group = title.group;
      if (!title.ui_readonly) {
        row_ = $.yqDgEditor(row_, title.ui_type, title.ui_mask)
      }
      else {
        row_.ui_type = title.ui_type;
        row_.ui_mask = title.ui_mask;
      }

      rows.push(row_);
    }

    opt.$attredit.propertygrid("loadData", rows);
    $("#btn_d_item_del").linkbutton("enable");
  }

  //获取编辑区域格式解码后的html
  function update_GetHtml($object, $inner) {
    var $div = $("<div></div>");
    $div.append($inner.parent().parent().prop("outerHTML"));
    return getHtml($object, $div);
  }

  //更新编辑器
  function update_UppEdit($object, $inner, f_html) {
    var opt = options($object);

    var cont_level = parseInt($inner.parent().parent().parent().attr("cont_level"));
    var $new_inner = $(f_html);
    if ($inner.attr("id") === undefined) {
      $new_inner.attr("_n", $inner.attr("_n"));
    } else {
      $new_inner.attr("id", $inner.attr("id"));
    }

    console.log($new_inner.prop("outerHTML"));
    //占位添加到old后
    var $tmp_edit = $("<div></div>");
    $inner.parent().parent().after($tmp_edit);
    //删除old
    update_del($object, $inner.parent().parent());
    var $new_edit = initEdit($object, $new_inner.prop("outerHTML"), cont_level);
    //添加到占位后面
    $tmp_edit.after($new_edit);
    //移除占位
    $tmp_edit.remove();
    item_click($object, $new_edit);
  }

  function update_del($object, $html) {
    var opt = options($object);

    var $items = $html.find(".d_view");
    for (let i = 0; i < $items.length; i++) {
      const $item = $($items[i]);
      const _id = $($item.children()[0]).attr("id");
      if (!(_id === undefined)) {
        var $d_item = opt.$sm.find('[_id="' + _id + '"]');
        $d_item.draggable("enable");
        $d_item.removeClass("disable");
      }
    }
    $html.remove();
  }

  //获取模板
  function getHtml($object, $obj) {
    var opt = options($object);

    var $c_obj = get_html($($obj.prop("outerHTML")));
    return htmlFormat($c_obj.html())
    function get_html($obj) {
      var $c_s = $obj.children();
      for (let i = 0; i < $c_s.length; i++) {
        const $el = $($c_s[i]);
        if ($el.hasClass("d_item")) {
          var $view = $el.children(".d_view");
          $el.remove();
          var $ch = get_html($view.children());

          $obj.append($ch);
        } else {
          var $ch = get_html($el);
          $obj.append($ch);
        }
      }

      if ($obj.hasClass("droppable")) {
        $obj.removeClass("droppable");
        $obj.removeAttr("cont_level");
        $obj.removeAttr("cont_num");
      }
      if ($obj.hasClass("class") == "") {
        $obj.removeAttr("class");
      }
      return $obj;
    }
  }

  // html格式化（依赖外部库js-beautify）
  function htmlFormat(strs) {
    const selfClosingTags = ['input', 'img', 'hr', 'br', 'link', 'meta'];
    let left = null;
    let right = null;
    let str = "";
    const blank = "\t";
    const fmt = [];

    for (let i = 0; i < strs.length; i++) {
      if (strs[i] === "<") {
        left = i;
      } else if (strs[i] === ">") {
        right = i;
      }
      if (typeof left === "number" && typeof right === "number") {
        const tagContent = strs.slice(left, right + 1);

        // 处理自闭合标签
        if (selfClosingTags.some(tag => tagContent.toLowerCase().startsWith(`<${tag}`))) {
          if (!tagContent.endsWith("/>")) {
            const fixedTag = tagContent.slice(0, -1) + "/>";
            str += fmt.join("") + fixedTag;
          } else {
            str += fmt.join("") + tagContent;
          }
        } else if (strs[left + 1] === "/") {
          fmt.pop();
          str += fmt.join("") + tagContent;
        } else if (strs[right - 1] === "/") {
          str += fmt.join("") + tagContent;
        } else {
          str += fmt.join("") + tagContent;
          fmt.push(blank);
        }

        // 处理标签之间的文本内容
        for (let j = right + 1; j < strs.length; j++) {
          if (strs[j] === "<") {
            const textContent = strs.slice(right + 1, j).trim();
            if (textContent) {
              str += textContent;
            }
            break;
          }
        }

        str += "\n";
        left = null;
        right = null;
      }
    }
    return str;
  }
})(jQuery);